package rensoft.gwt.client.history;

import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.History;

import java.util.Map;

import static cs.java.lang.Lang.error;
import static cs.java.lang.Lang.iterate;
import static cs.java.lang.Lang.list;
import static cs.java.lang.Lang.map;
import static cs.java.lang.Lang.no;
import static cs.java.lang.Lang.set;
import static cs.java.lang.Lang.text;

import cs.java.collections.Mapped;
import cs.java.lang.HasService;
import cs.java.lang.KeyValue;
import cs.java.lang.Text;




import rensoft.gwt.client.lang.GwtBase;

public class HistoryItems extends GwtBase {

  private final Map<String, HistoryItem> items = map();

  public HistoryItem create(String key, String defaultValue) {
    HistoryItem item = items.get(key);
    if (no(item)) {
      items.put(key, item = new HistoryItemImpl(key, defaultValue) {
        @Override
        public void save(String value) {
          super.save(value);
          onItemChange();
        }
      });
      item.initialize(this);
    }
    return item;
  }

  @Override
  public void initialize(HasService parent) {
    super.initialize(parent);
    History.addValueChangeHandler(new ValueChangeHandler<String>() {
      public void onValueChange(ValueChangeEvent<String> event) {
        loadHistory(event.getValue());
      }
    });
    loadHistory(History.getToken());
  }

  private HistoryItem getSingleItem() {
    return list(items.values()).get(0);
  }

  private void loadAllKeyValueHistoryItems(String[] historyItems) {
    for (String item : historyItems)
      items.get(parseItem(item).key).load(parseItem(item).value);
  }

  private void loadHistory(String historyToken) {
    if (historyToken.startsWith("!")) historyToken = historyToken.substring(1);
    try {
      String[] historyItems = historyToken.split(":");
      boolean isLoadSingleValue = items.size() == 1 && historyItems.length > 0;
      if (isLoadSingleValue)
        loadSingleValueFromHistoryItems(historyItems);
      else loadAllKeyValueHistoryItems(historyItems);
    } catch (Exception e) {
      error(e);
      for (HistoryItem item : items.values())
        item.loadDefault();
    }
  }

  private void loadSingleValueFromHistoryItems(String[] historyItems) {
    getSingleItem().load(parseItem(historyItems[0]).value);
  }

  private void onItemChange() {
    saveHistory();
  }

  private KeyValue parseItem(String historyItem) {
    String[] keyvalueSplit = historyItem.split("=");
    if (keyvalueSplit.length == 2) return new KeyValue(keyvalueSplit[0], keyvalueSplit[1]);
    return new KeyValue(null, keyvalueSplit[0]);
  }

  private void saveHistory() {
    Text token = text();
    if (items.size() == 1)
      token.add(getSingleItem().getValue());
    else {
      for (Mapped<String, HistoryItem> item : iterate(items)) {
        String value = item.value().getValue();
        if (value.isEmpty()) continue;
        token.add(item.key()).add("=").add(value).add(":");
      }
      if (set(token)) token.cutEnd(1);
    }
    if (token.isEmpty())
      History.newItem("", false);
    else History.newItem("!" + token.toString(), false);
  }
}
